package xyz.fefine;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

/**
 * Created by feng_ on 2016/9/4.
 * 按照运算符优先级分析法的语法分析器
 */
public class OpPrecedenceParser {

    private Lexer lexer;
    private HashMap<String,Precedence> operators;

    public static class Precedence{

        int value;
        boolean leftAssoc;      //左关系符

        public Precedence(int value, boolean leftAssoc) {
            this.value = value;
            this.leftAssoc = leftAssoc;
        }
    }

    public OpPrecedenceParser(Lexer lexer) {
        this.lexer = lexer;
        operators = new HashMap<>();        //运算符优先级
        operators.put(">",new Precedence(1,true));
        operators.put("<",new Precedence(1,true));
        operators.put(">=",new Precedence(1,true));
        operators.put("<=",new Precedence(1,true));
        operators.put("==",new Precedence(1,true));
        operators.put("+",new Precedence(2,true));
        operators.put("-",new Precedence(2,true));
        operators.put("*",new Precedence(3,true));
        operators.put("/",new Precedence(3,true));
        operators.put("^",new Precedence(4,false));
    }

    public ASTree expression() throws ParseException{
        ASTree asTree = factor();
        Precedence next;
        //while 待定
        while ((next = nextOperator()) != null) {
            asTree = doShift(asTree,next.value);
        }
        return asTree;
    }

    /**
     * 向右移动
     * @param left
     * @param pre
     * @return
     * @throws ParseException
     */
    public ASTree doShift(ASTree left, int pre) throws ParseException {
        ASTLeaf op = new ASTLeaf(lexer.read());
        ASTree mid = factor();
        Precedence next;
        while ((next = nextOperator()) != null && !rightIsExpr(pre, next.value)) {
            mid = doShift(mid,next.value);
//            mid = new BinaryExpr(Arrays.asList());
        }

        return new BinaryExpr(Arrays.asList(left,op,mid));

    }

    /**
     * 判断优先级
     * @param pre
     * @param next
     * @return
     */
    public boolean rightIsExpr(int pre, int next) {
        if (pre > next) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 读取下一个操作符
     * @return
     * @throws ParseException
     */
    public Precedence nextOperator() throws ParseException{
        Token token = lexer.peek(0);
        if (token.isIdentifier()) {
            return operators.get(token.getString());
        } else {
            return null;
        }
    }

    public ASTree factor() throws ParseException{

        if (isToken("(")) {
            token("(");
            ASTree asTree = expression();
            token(")");
            return asTree;
        } else {
            Token token = lexer.read();
            //System.out.println(token.getString());
            if (token.isNumber()) {
                NumberLiteral num = new NumberLiteral(token);
                return num;
            } else {
                throw new ParseException(token);
            }

        }
    }

    public void token(String name) throws ParseException{
        Token token = lexer.read();
        //不是标识符
        if (!token.isIdentifier() || name.equals(token.getString())) {
            throw new ParseException(token);
        }
    }

    /**
     * 判断是否为标识符并且名字相同
     * @param name 标识符名称
     * @return
     * @throws ParseException
     */
    public boolean isToken(String name) throws ParseException{
        Token token = lexer.peek(0);
        return token.isIdentifier()&&name.equals(token.getString());
    }

    public static void main(String[] args) throws ParseException{
        Lexer lexer = new Lexer(new CodeDialog());
        OpPrecedenceParser op = new OpPrecedenceParser(lexer);
        ASTree asTree = op.expression();
        System.out.println(asTree.toString());
        //test success
    }

}
